package com.xingchi.tornado.security.model;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.xingchi.tornado.security.enums.LoginTypeEnum;
import com.xingchi.tornado.security.service.LoginSourceService;
import com.xingchi.tornado.security.service.LoginTypeManager;
import com.xingchi.tornado.security.service.LoginTypeService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.security.core.Authentication;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.DataBinder;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

/**
 * 登录参数
 *
 * @author xingchi
 * @date 2025/3/9 20:31
 */
@Data
@Slf4j
public class LoginParameter {

    /**
     * 登录来源{@link LoginTypeService#getCode()}
     */
    private Integer loginType;

    /**
     * 登录来源 {@link LoginSourceService#getCode()}
     */
    private Integer loginSource;

    /**
     * 凭证信息
     */
    private Map<String, String> credentials;

    /**
     * 获取凭证信息
     *
     * @param <T> 认证类型 {@link LoginTypeEnum#getClazz()}
     * @return 认证信息
     */
    @SuppressWarnings("unchecked")
    @JsonIgnore
    public <T extends Authentication> T getAuthentication() {

        if (CollectionUtils.isEmpty(credentials)) {
            throw new IllegalArgumentException("登录凭证不能为空");
        }

        LoginTypeService loginTypeService = LoginTypeManager.getInstance(loginType);

        T instance;
        try {
            Constructor<? extends Authentication> declaredConstructor = loginTypeService.getAuthenticationClass().getDeclaredConstructor();
            declaredConstructor.setAccessible(true);
            instance = (T) declaredConstructor.newInstance();
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            log.error("无法构建登录参数对象，类型[{}]", loginTypeService.getAuthenticationClass().getName(), e);
            throw new IllegalArgumentException(e);
        }
        DataBinder dataBinder = new DataBinder(instance);
        // 忽略实体中没有的属性
        dataBinder.setIgnoreUnknownFields(true);

        // 对象转换
        MutablePropertyValues propertyValues = new MutablePropertyValues(credentials);
        dataBinder.bind(propertyValues);

        return instance;
    }

}
